<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Permissions-Policy" content="microphone=*">
    <title>会议助手</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: #ffffff;
            color: #333333;
            min-height: 100vh;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            min-height: 100vh;
        }

        /* 顶部标题区域 */
        .header {
            padding: 24px 32px;
            border-bottom: 1px solid #e5e5e5;
        }

        .header-content {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 8px;
        }

        .title {
            font-size: 24px;
            font-weight: 600;
            color: #333333;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .edit-icon {
            width: 16px;
            height: 16px;
            cursor: pointer;
            opacity: 0.6;
        }

        .edit-icon:hover {
            opacity: 1;
        }

        .datetime {
            font-size: 14px;
            color: #666666;
        }

        /* 标签页导航 */
        .tabs {
            display: flex;
            border-bottom: 1px solid #e5e5e5;
            padding: 0 32px;
        }

        .tab {
            padding: 16px 24px;
            font-size: 16px;
            color: #666666;
            cursor: pointer;
            border-bottom: 2px solid transparent;
            transition: all 0.2s ease;
        }

        .tab:hover {
            color: #333333;
        }

        .tab.active {
            color: #333333;
            border-bottom-color: #333333;
        }

        /* 录音控制面板 */
        .recording-panel {
            padding: 20px 32px;
            background: #f8f9fa;
            border-bottom: 1px solid #e5e5e5;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .recording-status {
            display: flex;
            align-items: center;
            gap: 20px;
        }

        .status-indicator {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .status-dot {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #dc3545;
            transition: background-color 0.3s ease;
        }

        .status-dot.recording {
            background: #28a745;
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }

        .recording-timer {
            font-size: 16px;
            font-weight: 600;
            color: #333;
            font-family: monospace;
        }

        .recording-buttons {
            display: flex;
            gap: 12px;
        }

        .recording-btn {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 12px 20px;
            border: none;
            border-radius: 8px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            min-width: 120px;
            justify-content: center;
        }

        .recording-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .start-btn {
            background: #28a745;
            color: white;
        }

        .start-btn:hover:not(:disabled) {
            background: #218838;
            transform: translateY(-1px);
        }

        .stop-btn {
            background: #dc3545;
            color: white;
        }

        .stop-btn:hover:not(:disabled) {
            background: #c82333;
            transform: translateY(-1px);
        }

        .speaker-btn {
            background: #6c757d;
            color: white;
        }

        .speaker-btn:hover:not(:disabled) {
            background: #5a6268;
            transform: translateY(-1px);
        }

        .btn-icon {
            width: 16px;
            height: 16px;
        }

        /* 音频播放器 */
        .audio-player {
            padding: 24px 32px;
            border-bottom: 1px solid #e5e5e5;
        }

        .progress-container {
            position: relative;
            margin-bottom: 16px;
        }

        .progress-bar {
            width: 100%;
            height: 4px;
            background: #e5e5e5;
            border-radius: 2px;
            position: relative;
            cursor: pointer;
        }

        .progress-fill {
            height: 100%;
            background: #333333;
            border-radius: 2px;
            width: 0%;
            transition: width 0.1s ease;
        }

        .progress-handle {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: 12px;
            height: 12px;
            background: #333333;
            border-radius: 50%;
            cursor: pointer;
            left: 0%;
        }

        .player-controls {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .time-display {
            font-size: 14px;
            color: #666666;
            font-family: monospace;
        }

        .controls {
            display: flex;
            align-items: center;
            gap: 16px;
        }

        .control-btn {
            width: 32px;
            height: 32px;
            border: none;
            background: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
            transition: background-color 0.2s ease;
        }

        .control-btn:hover {
            background: #f5f5f5;
        }

        .control-icon {
            width: 16px;
            height: 16px;
        }

        .delete-btn {
            margin-left: auto;
        }


        /* 转录内容区域 */
        .transcript-area {
            padding: 24px 32px;
            flex: 1;
            overflow-y: auto;
        }

        .transcript-item {
            margin-bottom: 16px;
            display: flex;
            align-items: flex-start;
            gap: 12px;
        }

        .speaker-label {
            font-weight: 600;
            color: #333333;
            min-width: 60px;
        }

        .transcript-text {
            flex: 1;
            line-height: 1.5;
        }

        .transcript-time {
            font-size: 12px;
            color: #999999;
            margin-left: auto;
        }

        .copy-btn {
            position: fixed;
            top: 24px;
            right: 24px;
            width: 40px;
            height: 40px;
            border: none;
            background: #f5f5f5;
            border-radius: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.2s ease;
        }

        .copy-btn:hover {
            background: #e5e5e5;
        }

        .copy-icon {
            width: 16px;
            height: 16px;
        }

        /* 隐藏的控制面板 */
        .control-panel {
            display: none;
        }

        .status-indicator {
            display: none;
        }

        /* 通知样式 */
        .notifications {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1000;
        }

        .notification {
            background: white;
            border-radius: 8px;
            padding: 12px 16px;
            margin-bottom: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
            border-left: 4px solid #4facfe;
            max-width: 300px;
            animation: slideIn 0.3s ease;
        }

        @keyframes slideIn {
            from {
                transform: translateX(100%);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }

        .notification.success {
            border-left-color: #28a745;
        }

        .notification.warning {
            border-left-color: #ffc107;
        }

        .notification.error {
            border-left-color: #dc3545;
        }

        /* 调试信息 */
        .debug-info {
            display: none;
        }

        /* 内容区域样式 */
        .content-area {
            padding: 24px 32px;
            flex: 1;
            overflow-y: auto;
            max-height: calc(100vh - 400px);
        }

        .markdown-content {
            line-height: 1.6;
            color: #333;
        }

        .markdown-content h1,
        .markdown-content h2,
        .markdown-content h3,
        .markdown-content h4,
        .markdown-content h5,
        .markdown-content h6 {
            margin: 20px 0 10px 0;
            font-weight: 600;
            color: #333;
        }

        .markdown-content h1 {
            font-size: 24px;
            border-bottom: 2px solid #e5e5e5;
            padding-bottom: 10px;
        }

        .markdown-content h2 {
            font-size: 20px;
            border-bottom: 1px solid #e5e5e5;
            padding-bottom: 8px;
        }

        .markdown-content h3 {
            font-size: 18px;
        }

        .markdown-content p {
            margin: 12px 0;
        }

        .markdown-content ul,
        .markdown-content ol {
            margin: 12px 0;
            padding-left: 24px;
        }

        .markdown-content li {
            margin: 6px 0;
        }

        .markdown-content blockquote {
            margin: 16px 0;
            padding: 12px 16px;
            background: #f8f9fa;
            border-left: 4px solid #4facfe;
            border-radius: 4px;
        }

        .markdown-content code {
            background: #f1f3f4;
            padding: 2px 6px;
            border-radius: 3px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 0.9em;
        }

        .markdown-content pre {
            background: #f8f9fa;
            padding: 16px;
            border-radius: 8px;
            overflow-x: auto;
            margin: 16px 0;
        }

        .markdown-content pre code {
            background: none;
            padding: 0;
        }

        .markdown-content table {
            width: 100%;
            border-collapse: collapse;
            margin: 16px 0;
        }

        .markdown-content th,
        .markdown-content td {
            border: 1px solid #e5e5e5;
            padding: 8px 12px;
            text-align: left;
        }

        .markdown-content th {
            background: #f8f9fa;
            font-weight: 600;
        }

        .markdown-content a {
            color: #4facfe;
            text-decoration: none;
        }

        .markdown-content a:hover {
            text-decoration: underline;
        }

        .markdown-content strong {
            font-weight: 600;
        }

        .markdown-content em {
            font-style: italic;
        }

        .loading-placeholder {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 60px 20px;
            color: #666;
        }

        .loading-placeholder .loading {
            margin-bottom: 16px;
        }

        .loading-placeholder p {
            margin: 0;
            font-size: 14px;
        }

        /* 洞察子项样式 */
        .insights-sections {
            margin-top: 20px;
        }

        .insight-section {
            margin-bottom: 32px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 12px;
            border-left: 4px solid #4facfe;
            transition: all 0.3s ease;
        }

        .insight-section:hover {
            background: #f1f3f4;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
        }

        .insight-title {
            margin: 0 0 16px 0;
            font-size: 18px;
            font-weight: 600;
            color: #333;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .insight-content {
            line-height: 1.6;
            color: #555;
        }

        .insight-content h1,
        .insight-content h2,
        .insight-content h3,
        .insight-content h4,
        .insight-content h5,
        .insight-content h6 {
            margin: 16px 0 8px 0;
            font-weight: 600;
            color: #333;
        }

        .insight-content h1 {
            font-size: 20px;
            border-bottom: 2px solid #e5e5e5;
            padding-bottom: 8px;
        }

        .insight-content h2 {
            font-size: 18px;
            border-bottom: 1px solid #e5e5e5;
            padding-bottom: 6px;
        }

        .insight-content h3 {
            font-size: 16px;
        }

        .insight-content p {
            margin: 12px 0;
        }

        .insight-content ul,
        .insight-content ol {
            margin: 12px 0;
            padding-left: 24px;
        }

        .insight-content li {
            margin: 6px 0;
        }

        .insight-content blockquote {
            margin: 16px 0;
            padding: 12px 16px;
            background: #ffffff;
            border-left: 4px solid #4facfe;
            border-radius: 4px;
        }

        .insight-content code {
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 3px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 0.9em;
        }

        .insight-content pre {
            background: #ffffff;
            padding: 16px;
            border-radius: 8px;
            overflow-x: auto;
            margin: 16px 0;
            border: 1px solid #e5e5e5;
        }

        .insight-content pre code {
            background: none;
            padding: 0;
        }

        .insight-content strong {
            font-weight: 600;
        }

        .insight-content em {
            font-style: italic;
        }

        /* 暂无数据样式 */
        .no-data-placeholder {
            text-align: center;
            color: #999;
            font-style: italic;
            padding: 40px 20px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px dashed #dee2e6;
        }


        @media (max-width: 768px) {
            .header {
                padding: 16px 20px;
            }
            
            .tabs {
                padding: 0 20px;
                overflow-x: auto;
            }
            
            .tab {
                padding: 12px 16px;
                white-space: nowrap;
            }
            
            .recording-panel {
                padding: 16px 20px;
                flex-direction: column;
                gap: 16px;
            }
            
            .recording-status {
                justify-content: center;
            }
            
            .recording-buttons {
                justify-content: center;
            }
            
            .audio-player {
                padding: 16px 20px;
            }
            
            .transcript-area {
                padding: 16px 20px;
            }
        }
    </style>
</head>
<body>
    <div class="notifications" id="notifications"></div>
    
    <div class="container">
        <!-- 顶部标题区域 -->
        <div class="header">
            <div class="header-content">
                <div class="title">
                    会议助手
                    <svg class="edit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                        <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                    </svg>
                </div>
            </div>
            <!-- <div class="datetime">2025年9月17日 13:28:31</div> -->
        </div>

        <!-- 标签页导航 -->
        <div class="tabs">
            <div class="tab" data-tab="wiki">会议总结</div>
            <div class="tab" data-tab="insights">洞察</div>
            <div class="tab" data-tab="keypoints">关键要点</div>
            <div class="tab" data-tab="todos">待办事项</div>
            <div class="tab active" data-tab="transcript">转录</div>
        </div>

        <!-- 录音控制面板 -->
        <div class="recording-panel">
            <div class="recording-status">
                <div class="status-indicator">
                    <div class="status-dot" id="statusDot"></div>
                    <span id="statusText">准备就绪</span>
                </div>
                <div class="recording-timer" id="recordingTimer">00:00</div>
            </div>
            <div class="recording-buttons">
                <button class="recording-btn start-btn" id="startRecordingBtn">
                    <svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <circle cx="12" cy="12" r="10"></circle>
                        <polygon points="10,8 16,12 10,16 10,8"></polygon>
                    </svg>
                    开始录音
                </button>
                <button class="recording-btn stop-btn" id="stopRecordingBtn" disabled>
                    <svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <rect x="6" y="6" width="12" height="12" rx="2"></rect>
                    </svg>
                    停止录音
                </button>
            </div>
        </div>

        <!-- 音频播放器 -->
        <div class="audio-player">
            <div class="progress-container">
                <div class="progress-bar" id="progressBar">
                    <div class="progress-fill" id="progressFill"></div>
                    <div class="progress-handle" id="progressHandle"></div>
                </div>
            </div>
            <div class="player-controls">
                <div class="time-display" id="currentTime">00:00:00</div>
                <div class="controls">
                    <button class="control-btn" id="rewindBtn">
                        <svg class="control-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <polygon points="11 19 2 12 11 5 11 19"></polygon>
                            <polygon points="22 19 13 12 22 5 22 19"></polygon>
                        </svg>
                    </button>
                    <button class="control-btn" id="playBtn">
                        <svg class="control-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <polygon points="5 3 19 12 5 21 5 3"></polygon>
                        </svg>
                    </button>
                    <button class="control-btn" id="forwardBtn">
                        <svg class="control-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <polygon points="13 19 22 12 13 5 13 19"></polygon>
                            <polygon points="2 19 11 12 2 5 2 19"></polygon>
                        </svg>
                    </button>
                </div>
                <button class="control-btn delete-btn" id="deleteBtn">
                    <svg class="control-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <polyline points="3,6 5,6 21,6"></polyline>
                        <path d="M19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
                    </svg>
                </button>
            </div>
        </div>


        <!-- 转录内容区域 -->
        <div class="transcript-area" id="transcriptArea">
            <div style="color: #6c757d; text-align: center; margin-top: 100px;">点击"开始录音"开始实时转写...</div>
        </div>

        <!-- 维基内容区域 -->
        <div class="content-area" id="wikiArea" style="display: none;">
            <div class="markdown-content" id="wikiContent">
                <div class="loading-placeholder">
                    <div class="loading"></div>
                    <p>正在生成维基内容...</p>
                </div>
            </div>
        </div>

        <!-- 洞察内容区域 -->
        <div class="content-area" id="insightsArea" style="display: none;">
            <div class="markdown-content" id="insightsContent">
                <div class="loading-placeholder">
                    <div class="loading"></div>
                    <p>正在生成洞察内容...</p>
                </div>
                
                <!-- 洞察子项 -->
                <div class="insights-sections">
                    <!-- 摘要子项 -->
                    <div class="insight-section" id="abstractSection">
                        <h3 class="insight-title">📋 摘要</h3>
                        <div class="insight-content" id="abstractContent">
                            <div class="no-data-placeholder">暂无数据</div>
                        </div>
                    </div>
                    
                    <!-- 建议子项 -->
                    <div class="insight-section" id="adviceSection">
                        <h3 class="insight-title">💡 AI建议</h3>
                        <div class="insight-content" id="adviceContent">
                            <div class="no-data-placeholder">暂无数据</div>
                        </div>
                    </div>
                    
                    <!-- 风险与依赖子项 -->
                    <div class="insight-section" id="riskSection">
                        <h3 class="insight-title">⚠️ 风险与依赖</h3>
                        <div class="insight-content" id="riskContent">
                            <div class="no-data-placeholder">暂无数据</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 关键要点内容区域 -->
        <div class="content-area" id="keypointsArea" style="display: none;">
            <div class="markdown-content" id="keypointsContent">
                <div class="loading-placeholder">
                    <div class="loading"></div>
                    <p>正在生成关键要点...</p>
                </div>
            </div>
        </div>

        <!-- 待办事项内容区域 -->
        <div class="content-area" id="todosArea" style="display: none;">
            <div class="markdown-content" id="todosContent">
                <div class="loading-placeholder">
                    <div class="loading"></div>
                    <p>正在生成待办事项...</p>
                </div>
            </div>
        </div>

        <!-- 复制按钮 -->
        <button class="copy-btn" id="copyBtn">
            <svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
            </svg>
        </button>

        <!-- 隐藏的原始控制面板 -->
        <div class="control-panel">
            <button class="btn btn-primary" id="startBtn">开始录音</button>
            <button class="btn btn-secondary" id="stopBtn" disabled>停止录音</button>
            <button class="btn btn-success" id="summaryBtn" disabled>生成总结</button>
        </div>

        <!-- 隐藏的状态指示器 -->
        <div class="status-indicator">
            <div class="status-dot" id="statusDot"></div>
            <span id="statusText">准备就绪</span>
            <div class="timer" id="timer">00:00</div>
        </div>

        <!-- 隐藏的调试信息 -->
        <div class="debug-info" id="debugInfo">
            <div>连接状态: <span id="connectionStatus">未连接</span></div>
            <div>录音状态: <span id="recordingStatus">未录音</span></div>
            <div>句子计数: <span id="sentenceCount">0</span></div>
            <div>最后消息: <span id="lastMessage">无</span></div>
        </div>
    </div>

    <!-- 引入markdown渲染框架 -->
    <script src="https://cdn.jsdelivr.net/npm/marked@9.1.6/marked.min.js"></script>
    <!-- 引入配置文件 -->
    <script src="js/config.js"></script>
    <!-- 引入腾讯ASR WebSocket服务 -->
    <script src="js/tencent-asr-websocket.js"></script>
    <!-- 引入API服务 -->
    <script src="js/api-service.js"></script>
    <!-- 引入说话人识别服务 -->
    <script src="js/speaker-recognition-service.js"></script>
    <script src="js/meeting-assistant-client.js"></script>

    <script>
        class MeetingAssistant {
            constructor() {
                this.isRecording = false;
                this.isPlaying = false;
                this.mediaRecorder = null;
                this.audioChunks = [];
                this.audioBlob = null;
                this.audioUrl = null;
                this.audioElement = null;
                this.transcript = '';
                this.recordingStartTime = null;
                this.timerInterval = null;
                this.estimatedDuration = null; // 用于处理Infinity时长问题
                this.apiService = new APIService();
                this.agentService = new MeetingAssistantClient();
                // 说话人识别服务
                this.speakerService = new SpeakerRecognitionService();
                this.currentSpeaker = null;
                this.sentenceAudioBuffer = []; // 存储当前句子的音频数据
                this.sentenceStartTime = null; // 句子开始时间
                
                // 内容缓存，用于避免重复渲染
                this.contentCache = {
                    wiki: '',
                    insights: '',
                    keypoints: '',
                    todos: '',
                    abstract: '',
                    advice: '',
                    risk: ''
                };
                
                // 显示说话人识别模式
                console.log('说话人识别模式:', this.speakerService.mockMode ? '模拟模式' : '真实API模式');
                
                // 句子状态管理
                this.currentSentence = '';
                this.completedSentences = [];
                this.isNewSentence = true;
                this.sentenceStartTime = null;
                
                this.initializeElements();
                this.bindEvents();
                this.checkConfiguration();
                this.checkMicrophonePermission();
                this.initSocket();
            }

            initSocket() {  
                this.agentService.connect();
            }

            initializeElements() {
                // 隐藏的原始控制元素
                this.startBtn = document.getElementById('startBtn');
                this.stopBtn = document.getElementById('stopBtn');
                this.summaryBtn = document.getElementById('summaryBtn');
                this.timer = document.getElementById('timer');
                this.summaryContent = document.getElementById('summaryContent');
                this.notifications = document.getElementById('notifications');
                
                // 新的UI元素 - 录音控制
                this.statusDot = document.getElementById('statusDot');
                this.statusText = document.getElementById('statusText');
                this.recordingTimer = document.getElementById('recordingTimer');
                this.startRecordingBtn = document.getElementById('startRecordingBtn');
                this.stopRecordingBtn = document.getElementById('stopRecordingBtn');
                
                // 新的UI元素 - 播放控制
                this.playBtn = document.getElementById('playBtn');
                this.rewindBtn = document.getElementById('rewindBtn');
                this.forwardBtn = document.getElementById('forwardBtn');
                this.deleteBtn = document.getElementById('deleteBtn');
                this.copyBtn = document.getElementById('copyBtn');
                this.progressBar = document.getElementById('progressBar');
                this.progressFill = document.getElementById('progressFill');
                this.progressHandle = document.getElementById('progressHandle');
                this.currentTime = document.getElementById('currentTime');
                
                // 转录内容区域
                this.transcriptContent = document.getElementById('transcriptArea');
                
                // 标签页内容区域
                this.wikiArea = document.getElementById('wikiArea');
                this.insightsArea = document.getElementById('insightsArea');
                this.keypointsArea = document.getElementById('keypointsArea');
                this.todosArea = document.getElementById('todosArea');
                this.wikiContent = document.getElementById('wikiContent');
                this.insightsContent = document.getElementById('insightsContent');
                this.keypointsContent = document.getElementById('keypointsContent');
                this.todosContent = document.getElementById('todosContent');
                
                // 洞察子项元素
                this.abstractSection = document.getElementById('abstractSection');
                this.adviceSection = document.getElementById('adviceSection');
                this.riskSection = document.getElementById('riskSection');
                this.abstractContent = document.getElementById('abstractContent');
                this.adviceContent = document.getElementById('adviceContent');
                this.riskContent = document.getElementById('riskContent');
                
                // 标签页元素
                this.tabs = document.querySelectorAll('.tab');
                
                // 调试信息元素
                this.connectionStatus = document.getElementById('connectionStatus');
                this.recordingStatus = document.getElementById('recordingStatus');
                this.sentenceCount = document.getElementById('sentenceCount');
                this.lastMessage = document.getElementById('lastMessage');
            }

            bindEvents() {
                // 原始控制按钮事件（隐藏的按钮）
                this.startBtn.addEventListener('click', () => this.startRecording());
                this.stopBtn.addEventListener('click', () => this.stopRecording());
                this.summaryBtn.addEventListener('click', () => this.generateSummary());
                
                // 新的录音控制按钮事件
                this.startRecordingBtn.addEventListener('click', () => this.startRecording());
                this.stopRecordingBtn.addEventListener('click', () => this.stopRecording());
                
                // 新的UI元素事件
                this.playBtn.addEventListener('click', () => this.togglePlayback());
                this.rewindBtn.addEventListener('click', () => this.rewind15s());
                this.forwardBtn.addEventListener('click', () => this.forward15s());
                this.deleteBtn.addEventListener('click', () => this.deleteRecording());
                this.copyBtn.addEventListener('click', () => this.copyTranscript());
                
                // 标签页切换事件
                this.tabs.forEach(tab => {
                    tab.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        this.switchTab(tab.dataset.tab);
                    });
                });
                
                // 进度条点击事件
                this.progressBar.addEventListener('click', (e) => this.seekToPosition(e));
            }

            async startRecording() {
                try {
                    // 检查浏览器支持
                    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
                        throw new Error('您的浏览器不支持麦克风访问功能，请使用现代浏览器（Chrome、Firefox、Safari等）');
                    }

                    // 检查是否在HTTPS环境下（生产环境要求）
                    if (location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
                        console.warn('警告：在非HTTPS环境下，某些浏览器可能不支持麦克风访问');
                    }

                    // 显示权限请求提示
                    this.showNotification('正在请求麦克风权限...', 'info');

                    // 获取麦克风权限并开始录制
                    const stream = await navigator.mediaDevices.getUserMedia({ 
                        audio: {
                            echoCancellation: true,
                            noiseSuppression: true,
                            autoGainControl: true,
                            sampleRate: 16000
                        } 
                    });
                    
                    // 创建MediaRecorder实例，使用最佳支持的格式
                    let mimeType = 'audio/webm';
                    if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) {
                        mimeType = 'audio/webm;codecs=opus';
                    } else if (MediaRecorder.isTypeSupported('audio/mp4')) {
                        mimeType = 'audio/mp4';
                    } else if (MediaRecorder.isTypeSupported('audio/wav')) {
                        mimeType = 'audio/wav';
                    }
                    
                    this.mediaRecorder = new MediaRecorder(stream, { mimeType: mimeType });
                    this.audioChunks = [];
                    console.log('MediaRecorder创建完成，使用格式:', mimeType);
                    
                    // 监听数据可用事件
                    this.mediaRecorder.ondataavailable = (event) => {
                        if (event.data.size > 0) {
                            this.audioChunks.push(event.data);
                        }
                    };
                    
                    // 监听录制停止事件
                    this.mediaRecorder.onstop = () => {
                        // 创建音频Blob，尝试多种格式
                        let mimeType = 'audio/webm';
                        if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) {
                            mimeType = 'audio/webm;codecs=opus';
                        } else if (MediaRecorder.isTypeSupported('audio/mp4')) {
                            mimeType = 'audio/mp4';
                        } else if (MediaRecorder.isTypeSupported('audio/wav')) {
                            mimeType = 'audio/wav';
                        }
                        
                        this.audioBlob = new Blob(this.audioChunks, { type: mimeType });
                        this.audioUrl = URL.createObjectURL(this.audioBlob);
                        console.log('音频Blob创建完成，MIME类型:', mimeType, '大小:', this.audioBlob.size, 'bytes');
                        
                        // 创建音频元素用于播放
                        if (this.audioElement) {
                            this.audioElement.remove();
                        }
                        this.audioElement = new Audio(this.audioUrl);
                        
                        // 设置音频事件监听
                        this.audioElement.onloadedmetadata = () => {
                            console.log('音频元数据加载完成，时长:', this.audioElement.duration);
                            this.updateAudioDuration();
                        };
                        
                        this.audioElement.oncanplaythrough = () => {
                            console.log('音频可以播放，时长:', this.audioElement.duration);
                            this.updateAudioDuration();
                        };
                        
                        this.audioElement.onloadeddata = () => {
                            console.log('音频数据加载完成，时长:', this.audioElement.duration);
                            this.updateAudioDuration();
                        };
                        
                        this.audioElement.oncanplay = () => {
                            console.log('音频可以开始播放，时长:', this.audioElement.duration);
                            this.updateAudioDuration();
                        };
                        
                        this.audioElement.onended = () => {
                            this.isPlaying = false;
                            this.updatePlayButton();
                            this.stopProgressUpdate();
                            this.showNotification('录音播放完成', 'info');
                        };
                        
                        // 设置进度更新事件监听器
                        this.setupProgressUpdate();
                        
                        // 立即尝试获取音频时长
                        setTimeout(() => {
                            this.updateAudioDuration();
                        }, 100);
                        
                        // 停止所有音频轨道
                        stream.getTracks().forEach(track => track.stop());
                        
                        console.log('录音完成，音频文件大小:', this.audioBlob.size, 'bytes');
                        this.showNotification('录音已保存', 'success');
                        
                        // 等待音频元数据加载
                        setTimeout(() => {
                            if (this.audioElement && this.audioElement.duration && isFinite(this.audioElement.duration)) {
                                console.log('最终音频时长:', this.audioElement.duration);
                            } else {
                                console.warn('音频时长无效:', this.audioElement ? this.audioElement.duration : 'no audio element');
                            }
                        }, 1000);
                    };
                    
                    // 开始录制
                    this.mediaRecorder.start(1000); // 每秒收集一次数据
                    
                    // 使用WebSocket实时ASR
                    const success = await this.apiService.startRealTimeASR();
                    
                    if (!success) {
                        throw new Error('启动实时ASR失败');
                    }

                    // 设置ASR事件回调
                    this.apiService.onRecognitionResult = (result) => {
                        console.log('收到识别结果回调:', result);
                        this.updateDebugInfo('识别结果', result);
                        if (result.voice_text_str) {
                            this.handleRecognitionResult(result);
                        }
                    };

                    this.agentService.handleNotification = (type, text) => {
                        if (text) {
                            this.handleNotificationResult(type, text);
                        }
                    };

                    this.apiService.onSentenceEnd = (result) => {
                        console.log('收到句子结束回调:', result);
                        this.updateDebugInfo('句子结束', result);
                        if (result.voice_text_str) {
                            this.handleSentenceEnd(result);
                        }
                    };

                    // 设置音频数据回调用于说话人识别
                    this.apiService.onAudioData = (audioData) => {
                        this.handleAudioDataForSpeakerRecognition(audioData);
                    };

                    this.apiService.onError = (error) => {
                        console.error('ASR错误:', error);
                        this.showNotification('语音识别错误: ' + error.message, 'error');
                    };

                    this.isRecording = true;
                    this.recordingStartTime = Date.now();
                    this.transcript = '';
                    
                    // 重置句子状态
                    this.currentSentence = '';
                    this.completedSentences = [];
                    this.isNewSentence = true;
                    this.sentenceStartTime = null;
                    
                    // 重置音频播放器显示
                    this.currentTime.textContent = '00:00:00';
                    this.progressFill.style.width = '0%';
                    this.progressHandle.style.left = '0%';
                    
                    this.updateUI();
                    this.startTimer();
                    this.updateDebugInfo('开始录音', {});
                    
                    this.showNotification('开始实时录音转写', 'success');
                    
                } catch (error) {
                    console.error('录音启动失败:', error);
                    
                    // 根据不同的错误类型提供具体的解决方案
                    let errorMessage = '录音启动失败';
                    let solution = '';
                    
                    if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
                        errorMessage = '麦克风权限被拒绝';
                        solution = '解决方案：\n1. 点击浏览器地址栏左侧的锁图标或摄像头图标\n2. 选择"允许"麦克风权限\n3. 如果已拒绝，请点击"重置权限"或"清除设置"\n4. 刷新页面后重试\n\n如果问题持续，请检查浏览器设置中的麦克风权限';
                    } else if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {
                        errorMessage = '未找到麦克风设备';
                        solution = '请检查麦克风是否已连接并正常工作';
                    } else if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {
                        errorMessage = '麦克风被其他应用占用';
                        solution = '请关闭其他正在使用麦克风的应用程序，然后重试';
                    } else if (error.name === 'OverconstrainedError' || error.name === 'ConstraintNotSatisfiedError') {
                        errorMessage = '麦克风配置不支持';
                        solution = '请尝试使用其他麦克风设备或更新浏览器';
                    } else if (error.name === 'NotSupportedError') {
                        errorMessage = '浏览器不支持录音功能';
                        solution = '请使用现代浏览器（Chrome、Firefox、Safari等）';
                    } else if (error.name === 'SecurityError') {
                        errorMessage = '安全限制阻止了麦克风访问';
                        solution = '请确保在HTTPS环境下使用，或使用localhost访问';
                    } else {
                        errorMessage = error.message || '未知错误';
                        solution = '请检查麦克风权限和浏览器设置';
                    }
                    
                    // 显示详细的错误信息
                    this.showNotification(`${errorMessage}。${solution}`, 'error');
                    
                    // 在控制台输出更详细的调试信息
                    console.error('详细错误信息:', {
                        name: error.name,
                        message: error.message,
                        stack: error.stack,
                        userAgent: navigator.userAgent,
                        protocol: location.protocol,
                        hostname: location.hostname
                    });
                }
            }

            stopRecording() {
                if (this.isRecording) {
                    // 停止MediaRecorder
                    if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {
                        this.mediaRecorder.stop();
                    }
                    
                    // 停止WebSocket ASR
                    this.apiService.stopRealTimeASR();
                    
                    this.isRecording = false;
                    this.updateUI();
                    this.stopTimer();
                    
                    this.showNotification('录音已停止', 'warning');
                }
            }


            async generateSummary() {
                if (!this.transcript.trim()) return;
                
                try {
                    this.showNotification('正在生成会议总结...', 'info');
                    
                    // 调用ChatGPT API
                    const summary = await this.apiService.callChatGPT(this.transcript);
                    this.updateSummaryDisplay(summary);
                    
                    this.showNotification('会议总结已更新', 'success');
                } catch (error) {
                    console.error('生成总结失败:', error);
                    this.showNotification('生成总结失败，请检查API配置', 'error');
                }
            }

            updateTranscriptDisplay() {
                let html = '';
                
                // 显示已完成的句子
                this.completedSentences.forEach((sentenceData, index) => {
                    const timestamp = this.formatTimestamp(sentenceData.timestamp);
                    const speakerName = sentenceData.speaker || '未知说话人';
                    html += `
                        <div class="transcript-item">
                            <div class="speaker-label">${speakerName}:</div>
                            <div class="transcript-text">${sentenceData.text}</div>
                            <div class="transcript-time">${timestamp}</div>
                        </div>
                    `;
                });
                
                // 显示当前正在识别的句子（如果有）
                if (this.currentSentence) {
                    const currentTimestamp = this.formatTimestamp(this.sentenceStartTime || Date.now());
                    const currentSpeakerName = this.currentSpeaker || '未知说话人';
                    html += `
                        <div class="transcript-item">
                            <div class="speaker-label">${currentSpeakerName}:</div>
                            <div class="transcript-text">${this.currentSentence}<span class="cursor">|</span></div>
                            <div class="transcript-time">${currentTimestamp}</div>
                        </div>
                    `;
                }
                
                // 如果没有内容，显示提示
                if (this.completedSentences.length === 0 && !this.currentSentence) {
                    html = '<div style="color: #6c757d; text-align: center; margin-top: 100px;">点击"开始录音"开始实时转写...</div>';
                }
                
                this.transcriptContent.innerHTML = html;
                
                // 滚动到底部
                this.transcriptContent.scrollTop = this.transcriptContent.scrollHeight;
            }

            updateSummaryDisplay(summary) {
                this.summaryContent.innerHTML = `
                    <div class="section">
                        <h4>📋 会议总结</h4>
                        <p>${summary.meetingSummary}</p>
                    </div>
                    
                    <div class="section">
                        <h4>🎯 关键要点</h4>
                        <ul>
                            ${summary.keyPoints.map(point => `<li>${point}</li>`).join('')}
                        </ul>
                    </div>
                    
                    <div class="section">
                        <h4>✅ 行动项</h4>
                        <ul>
                            ${summary.actionItems.map(item => `<li>${item}</li>`).join('')}
                        </ul>
                    </div>
                    
                    <div class="section">
                        <h4>📅 下次会议</h4>
                        <p>${summary.nextMeeting}</p>
                    </div>
                `;
            }


            startTimer() {
                this.timerInterval = setInterval(() => {
                    const elapsed = Date.now() - this.recordingStartTime;
                    const minutes = Math.floor(elapsed / 60000);
                    const seconds = Math.floor((elapsed % 60000) / 1000);
                    const timeString = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
                    
                    // 更新隐藏的原始计时器
                    this.timer.textContent = timeString;
                    // 更新新的录音计时器
                    this.recordingTimer.textContent = timeString;
                }, 1000);
            }

            stopTimer() {
                if (this.timerInterval) {
                    clearInterval(this.timerInterval);
                    this.timerInterval = null;
                }
            }

            updateUI() {
                if (this.isRecording) {
                    // 隐藏的原始按钮
                    this.startBtn.disabled = true;
                    this.stopBtn.disabled = false;
                    
                    // 新的录音控制按钮
                    this.startRecordingBtn.disabled = true;
                    this.stopRecordingBtn.disabled = false;
                    this.statusDot.classList.add('recording');
                    this.statusText.textContent = '正在录音';
                } else {
                    // 隐藏的原始按钮
                    this.startBtn.disabled = false;
                    this.stopBtn.disabled = true;
                    
                    // 新的录音控制按钮
                    this.startRecordingBtn.disabled = false;
                    this.stopRecordingBtn.disabled = true;
                    this.statusDot.classList.remove('recording');
                    this.statusText.textContent = '准备就绪';
                }
                
                // 总结按钮：有转写内容时可用
                this.summaryBtn.disabled = !this.transcript.trim();
            }


            showNotification(message, type = 'info') {
                const notification = document.createElement('div');
                notification.className = `notification ${type}`;
                notification.textContent = message;
                
                this.notifications.appendChild(notification);
                
                setTimeout(() => {
                    notification.remove();
                }, this.apiService.config.APP.notificationDuration);
            }

            checkConfiguration() {
                const issues = this.apiService.checkConfiguration();
                if (issues.length > 0) {
                    this.showNotification(`配置问题: ${issues.join(', ')}`, 'warning');
                    console.warn('配置问题:', issues);
                }
            }

            async checkMicrophonePermission() {
                try {
                    // 检查浏览器支持
                    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
                        this.showNotification('您的浏览器不支持麦克风访问功能，请使用现代浏览器（Chrome、Firefox、Safari等）', 'warning');
                        return;
                    }

                    // 检查HTTPS环境 - 这是最重要的检查
                    if (location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
                        const httpsWarning = `
                            ⚠️ 麦克风权限问题检测到：
                            
                            🔒 当前使用HTTP协议，现代浏览器出于安全考虑，只允许在HTTPS环境下访问麦克风。
                            
                            💡 解决方案：
                            1. 使用HTTPS访问：https://10.151.124.38:8443
                            2. 或使用localhost：http://localhost:8000
                            3. 或使用我提供的HTTPS服务器脚本
                            
                            📋 详细步骤请查看控制台输出
                        `;
                        this.showNotification(httpsWarning, 'error');
                        console.error('❌ 麦克风权限被阻止：当前使用HTTP协议');
                        console.log('💡 解决方案：');
                        console.log('1. 运行HTTPS服务器：python3 https-server.py');
                        console.log('2. 访问：https://10.151.124.38:8443');
                        console.log('3. 浏览器会显示安全警告，点击"高级" -> "继续访问"');
                        return;
                    }

                    // 检查权限状态（如果支持）
                    if (navigator.permissions && navigator.permissions.query) {
                        try {
                            const permissionStatus = await navigator.permissions.query({ name: 'microphone' });
                            console.log('麦克风权限状态:', permissionStatus.state);
                            
                            if (permissionStatus.state === 'denied') {
                                const deniedMessage = `
                                    🚫 麦克风权限已被拒绝
                                    
                                    🔧 解决方法：
                                    1. 点击浏览器地址栏左侧的🔒或🎤图标
                                    2. 选择"允许"麦克风权限
                                    3. 如果已拒绝，点击"重置权限"
                                    4. 刷新页面后重试
                                    
                                    📱 不同浏览器的设置位置：
                                    • Chrome: 设置 → 隐私和安全 → 网站设置 → 麦克风
                                    • Firefox: 设置 → 隐私与安全 → 权限 → 麦克风
                                    • Safari: 偏好设置 → 网站 → 麦克风
                                `;
                                this.showNotification(deniedMessage, 'warning');
                            } else if (permissionStatus.state === 'granted') {
                                console.log('麦克风权限已授予');
                                this.showNotification('✅ 麦克风权限已授予，可以开始录音', 'success');
                            } else if (permissionStatus.state === 'prompt') {
                                this.showNotification('🎤 点击"开始录音"按钮时会请求麦克风权限', 'info');
                            }
                            
                            // 监听权限状态变化
                            permissionStatus.addEventListener('change', () => {
                                console.log('麦克风权限状态变化:', permissionStatus.state);
                                if (permissionStatus.state === 'granted') {
                                    this.showNotification('✅ 麦克风权限已授予', 'success');
                                } else if (permissionStatus.state === 'denied') {
                                    this.showNotification('❌ 麦克风权限被拒绝', 'error');
                                }
                            });
                        } catch (permError) {
                            console.log('无法查询麦克风权限状态:', permError);
                            this.showNotification('无法检查麦克风权限状态，请手动测试', 'info');
                        }
                    }

                } catch (error) {
                    console.error('检查麦克风权限失败:', error);
                    this.showNotification('检查麦克风权限时出错，请手动测试', 'warning');
                }
            }

            // 格式化时间戳
            formatTimestamp(timestamp) {
                if (!timestamp) return '';
                const date = new Date(timestamp);
                const hours = date.getHours().toString().padStart(2, '0');
                const minutes = date.getMinutes().toString().padStart(2, '0');
                const seconds = date.getSeconds().toString().padStart(2, '0');
                return `${hours}:${minutes}:${seconds}`;
            }
            // 处理Agent通知结果
            handleNotificationResult(type, text) {
                if(type == NotificationTypes.MeetingMinutes){
                    this.generateWikiContent(text);
                }
                // 处理洞察子项
                if(type == NotificationTypes.Abstract){
                    this.generateAbstractContent(text);
                }
                if(type == NotificationTypes.Advice){
                    this.generateAdviceContent(text);
                }
                if(type == NotificationTypes.RiskAndDependency){
                    this.generateRiskContent(text);
                }
                if(type == NotificationTypes.keypoint){
                   this.generateKeypointsContent(text);
                }
                if(type == NotificationTypes.ToDo){
                    this.generateTodosContent(text);
                }
            }   
            // 处理识别结果（中间态更新）
            handleRecognitionResult(result) {
                // 检查ASR文本是否为空
                if (!result.voice_text_str || result.voice_text_str.trim() === '') {
                    return; // 如果文本为空，不更新显示
                }
                
                if (this.isNewSentence) {
                    // 新句子开始，记录开始时间并清空音频缓冲区
                    this.currentSentence = result.voice_text_str;
                    this.sentenceStartTime = Date.now();
                    this.isNewSentence = false;
                    this.sentenceAudioBuffer = []; // 清空音频缓冲区，开始收集新句子的音频
                    console.log('新句子开始，清空音频缓冲区');
                } else {
                    // 更新当前句子
                    this.currentSentence = result.voice_text_str;
                }
                
                this.updateTranscriptDisplay();
            }

            // 处理句子结束
            async handleSentenceEnd(result) {
                // 完成当前句子
                const completedSentence = result.voice_text_str;
                const sentenceEndTime = Date.now();
                
                // 检查ASR文本是否为空，如果为空则不展示
                if (!completedSentence || completedSentence.trim() === '') {
                    console.log('句子结束但ASR文本为空，不展示');
                    // 清空当前句子，准备下一个句子
                    this.currentSentence = '';
                    this.sentenceStartTime = null;
                    this.isNewSentence = true;
                    this.updateTranscriptDisplay();
                    return;
                }
                this.agentService.sendASRText(completedSentence, result.audioId);

                // 在句子结束时进行说话人识别
                console.log('句子结束，开始说话人识别...');
                await this.performSpeakerRecognition();
                
          
                // 将句子数据存储为对象，包含文本、时间戳和说话人信息
                const sentenceData = {
                    text: completedSentence,
                    timestamp: this.sentenceStartTime || sentenceEndTime,
                    endTime: sentenceEndTime,
                    speaker: this.currentSpeaker || '未知说话人'
                };
                      // 发送当前句子文本和说话人到socket
                this.agentService.sendASRSpeakerText(this.currentSpeaker, completedSentence, result.audioId);
                this.completedSentences.push(sentenceData);
                this.transcript += completedSentence + ' ';
                
                // 清空当前句子，准备下一个句子
                this.currentSentence = '';
                this.sentenceStartTime = null;
                this.isNewSentence = true;
                
                this.updateTranscriptDisplay();
                this.updateUI(); // 更新UI状态，让总结按钮可用
                
                // 限制转写文本长度
                if (this.transcript.length > this.apiService.config.APP.maxTranscriptLength) {
                    this.transcript = this.transcript.slice(-this.apiService.config.APP.maxTranscriptLength);
                    // 同时限制已完成的句子数量
                    if (this.completedSentences.length > 50) {
                        this.completedSentences = this.completedSentences.slice(-50);
                    }
                }
                
                console.log('句子完成:', completedSentence, '时间:', this.formatTimestamp(sentenceData.timestamp));
            }

            // 更新调试信息
            updateDebugInfo(type, data) {
                if (this.lastMessage) {
                    this.lastMessage.textContent = `${type}: ${JSON.stringify(data).substring(0, 100)}...`;
                }
                if (this.connectionStatus) {
                    this.connectionStatus.textContent = this.apiService.isASRConnected ? '已连接' : '未连接';
                }
                if (this.recordingStatus) {
                    this.recordingStatus.textContent = this.isRecording ? '录音中' : '未录音';
                }
                if (this.sentenceCount) {
                    this.sentenceCount.textContent = this.completedSentences.length;
                }
            }

            // 新的UI功能方法
            togglePlayback() {
                if (this.audioElement && this.audioUrl) {
                    if (this.audioElement.paused) {
                        this.startPlayback();
                    } else {
                        this.pausePlayback();
                    }
                } else {
                    this.showNotification('没有可播放的录音文件', 'warning');
                }
            }

            startPlayback() {
                if (this.audioElement) {
                    console.log('开始播放音频:', {
                        duration: this.audioElement.duration,
                        currentTime: this.audioElement.currentTime,
                        paused: this.audioElement.paused,
                        readyState: this.audioElement.readyState
                    });
                    
                    // 确保进度更新事件监听器已设置
                    this.setupProgressUpdate();
                    
                    // 如果音频时长无效或为Infinity，尝试处理
                    if (!this.audioElement.duration || !isFinite(this.audioElement.duration) || this.audioElement.duration <= 0 || this.audioElement.duration === Infinity) {
                        console.log('音频时长无效或为Infinity，使用估算时长...');
                        
                        // 如果还没有估算时长，先获取
                        if (!this.estimatedDuration) {
                            this.handleInfinityDuration();
                        }
                        
                        // 直接播放，不等待
                        this.audioElement.play();
                        this.isPlaying = true;
                        this.updatePlayButton();
                        this.startProgressUpdate();
                        this.showNotification('开始播放录音（使用估算时长）', 'info');
                    } else {
                        this.audioElement.play();
                        this.isPlaying = true;
                        this.updatePlayButton();
                        this.startProgressUpdate();
                        this.showNotification('开始播放录音', 'info');
                    }
                }
            }

            pausePlayback() {
                if (this.audioElement) {
                    this.audioElement.pause();
                    this.isPlaying = false;
                    this.updatePlayButton();
                    this.stopProgressUpdate();
                    this.showNotification('暂停播放录音', 'info');
                }
            }

            updatePlayButton() {
                const playIcon = this.playBtn.querySelector('.control-icon');
                if (this.isPlaying) {
                    // 显示暂停图标
                    playIcon.innerHTML = `
                        <rect x="6" y="4" width="4" height="16"></rect>
                        <rect x="14" y="4" width="4" height="16"></rect>
                    `;
                } else {
                    // 显示播放图标
                    playIcon.innerHTML = `
                        <polygon points="5 3 19 12 5 21 5 3"></polygon>
                    `;
                }
            }

            updateAudioDuration() {
                if (this.audioElement && this.audioElement.duration && isFinite(this.audioElement.duration) && this.audioElement.duration > 0) {
                    console.log('音频时长已更新:', this.audioElement.duration);
                } else {
                    console.warn('音频时长无效:', this.audioElement ? this.audioElement.duration : 'no audio element');
                    
                    // 如果时长为Infinity，尝试使用备用方案
                    if (this.audioElement && this.audioElement.duration === Infinity) {
                        console.log('检测到Infinity时长，使用备用方案...');
                        this.handleInfinityDuration();
                    } else {
                    }
                }
            }

            handleInfinityDuration() {
                // 当音频时长为Infinity时的备用处理方案
                console.log('开始处理Infinity时长问题...');
                
                // 直接使用录音时间作为时长，这是最可靠的方法
                if (this.recordingStartTime) {
                    const recordingDuration = (Date.now() - this.recordingStartTime) / 1000;
                    this.estimatedDuration = recordingDuration;
                    console.log('使用录音时间作为估算时长:', this.estimatedDuration);
                } else {
                    // 如果没有录音时间，尝试从音频文件大小估算
                    if (this.audioBlob && this.audioBlob.size > 0) {
                        // 粗略估算：假设每秒音频约占用16KB（128kbps）
                        const estimatedDuration = this.audioBlob.size / 16000;
                        this.estimatedDuration = Math.max(estimatedDuration, 1); // 至少1秒
                        console.log('使用文件大小估算时长:', this.estimatedDuration);
                    } else {
                        console.warn('无法估算音频时长');
                    }
                }
            }

            setupProgressUpdate() {
                if (this.audioElement) {
                    // 使用timeupdate事件更新进度条
                    this.audioElement.ontimeupdate = () => {
                        if (this.audioElement && !this.audioElement.paused) {
                            const currentTime = this.audioElement.currentTime;
                            let duration = this.audioElement.duration;
                            
                            // 如果原始时长为Infinity，使用估算时长
                            if (!isFinite(duration) || duration === Infinity) {
                                duration = this.estimatedDuration;
                            }
                            
                            if (duration && isFinite(duration) && duration > 0) {
                                const progress = (currentTime / duration) * 100;
                                this.progressFill.style.width = progress + '%';
                                this.progressHandle.style.left = progress + '%';
                                this.currentTime.textContent = this.formatTime(currentTime);
                                
                                // 调试信息
                                console.log('进度更新:', {
                                    currentTime: currentTime,
                                    duration: duration,
                                    progress: progress.toFixed(2) + '%',
                                    usingEstimated: !isFinite(this.audioElement.duration)
                                });
                            }
                        }
                    };
                    
                    console.log('进度更新事件监听器已设置');
                }
            }

            startProgressUpdate() {
                // 由于已经使用了timeupdate事件，这里主要用于调试和备用
                this.progressInterval = setInterval(() => {
                    if (this.audioElement && !this.audioElement.paused) {
                        // 调试信息
                        if (Math.floor(this.audioElement.currentTime) % 5 === 0) {
                            console.log('播放状态检查:', {
                                currentTime: this.audioElement.currentTime,
                                duration: this.audioElement.duration,
                                paused: this.audioElement.paused,
                                readyState: this.audioElement.readyState
                            });
                        }
                    }
                }, 2000); // 减少频率，主要用于调试
            }

            stopProgressUpdate() {
                if (this.progressInterval) {
                    clearInterval(this.progressInterval);
                    this.progressInterval = null;
                }
            }

            formatTime(seconds) {
                // 检查输入是否有效
                if (!seconds || isNaN(seconds) || !isFinite(seconds)) {
                    return '00:00:00';
                }
                
                const hours = Math.floor(seconds / 3600);
                const minutes = Math.floor((seconds % 3600) / 60);
                const secs = Math.floor(seconds % 60);
                return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
            }

            rewind15s() {
                if (this.audioElement && this.audioElement.duration && isFinite(this.audioElement.duration)) {
                    this.audioElement.currentTime = Math.max(0, this.audioElement.currentTime - 15);
                    this.showNotification('后退15秒', 'info');
                } else {
                    this.showNotification('没有可播放的录音文件或音频时长无效', 'warning');
                }
            }

            forward15s() {
                if (this.audioElement && this.audioElement.duration && isFinite(this.audioElement.duration)) {
                    this.audioElement.currentTime = Math.min(this.audioElement.duration, this.audioElement.currentTime + 15);
                    this.showNotification('前进15秒', 'info');
                } else {
                    this.showNotification('没有可播放的录音文件或音频时长无效', 'warning');
                }
            }

            deleteRecording() {
                if (confirm('确定要删除这个录音吗？')) {
                    this.stopRecording();
                    this.completedSentences = [];
                    this.currentSentence = '';
                    this.transcript = '';
                    this.recordingTimer.textContent = '00:00';
                    
                    // 清理音频文件
                    if (this.audioUrl) {
                        URL.revokeObjectURL(this.audioUrl);
                        this.audioUrl = null;
                    }
                    if (this.audioElement) {
                        this.audioElement.remove();
                        this.audioElement = null;
                    }
                    this.audioBlob = null;
                    this.audioChunks = [];
                    
                    // 重置音频播放器显示
                    this.currentTime.textContent = '00:00:00';
                    this.progressFill.style.width = '0%';
                    this.progressHandle.style.left = '0%';
                    
                    this.updateTranscriptDisplay();
                    this.updateUI();
                    this.showNotification('录音已删除', 'warning');
                }
            }

            copyTranscript() {
                const transcriptText = this.completedSentences.map(s => s.text).join(' ');
                if (transcriptText.trim()) {
                    navigator.clipboard.writeText(transcriptText).then(() => {
                        this.showNotification('转录内容已复制到剪贴板', 'success');
                    }).catch(() => {
                        this.showNotification('复制失败', 'error');
                    });
                } else {
                    this.showNotification('没有可复制的内容', 'warning');
                }
            }

            switchTab(tabName) {
                console.log('切换到标签页:', tabName);
                
                // 移除所有活动状态
                this.tabs.forEach(tab => tab.classList.remove('active'));
                
                // 隐藏所有内容区域
                const transcriptArea = document.getElementById('transcriptArea');
                if (transcriptArea) transcriptArea.style.display = 'none';
                if (this.wikiArea) this.wikiArea.style.display = 'none';
                if (this.insightsArea) this.insightsArea.style.display = 'none';
                if (this.keypointsArea) this.keypointsArea.style.display = 'none';
                if (this.todosArea) this.todosArea.style.display = 'none';
                
                // 添加当前标签的活动状态
                const activeTab = document.querySelector(`[data-tab="${tabName}"]`);
                if (activeTab) {
                    activeTab.classList.add('active');
                }
                
                // 显示对应的内容区域
                switch(tabName) {
                    case 'transcript':
                        if (transcriptArea) {
                            transcriptArea.style.display = 'block';
                            console.log('显示转录区域');
                        }
                        break;
                    case 'wiki':
                        if (this.wikiArea) {
                            this.wikiArea.style.display = 'block';
                            console.log('显示维基区域');
                            // this.generateWikiContent();
                        }
                        break;
                    case 'insights':
                        if (this.insightsArea) {
                            this.insightsArea.style.display = 'block';
                            console.log('显示洞察区域');
                            
                            // 隐藏加载提示
                            const loadingPlaceholder = this.insightsContent.querySelector('.loading-placeholder');
                            if (loadingPlaceholder) {
                                loadingPlaceholder.style.display = 'none';
                            }
                        }
                        break;
                    case 'keypoints':
                        if (this.keypointsArea) {
                            this.keypointsArea.style.display = 'block';
                            console.log('显示关键要点区域');
                            // this.generateKeypointsContent();
                        }
                        break;
                    case 'todos':
                        if (this.todosArea) {
                            this.todosArea.style.display = 'block';
                            console.log('显示待办事项区域');
                            // this.generateTodosContent();
                        }
                        break;
                }
                
                this.showNotification(`切换到${tabName}标签`, 'info');
            }

            seekToPosition(e) {
                if (this.audioElement && this.audioElement.duration && isFinite(this.audioElement.duration)) {
                    const rect = this.progressBar.getBoundingClientRect();
                    const clickX = e.clientX - rect.left;
                    const percentage = (clickX / rect.width) * 100;
                    const newTime = (percentage / 100) * this.audioElement.duration;
                    
                    this.audioElement.currentTime = newTime;
                    this.progressFill.style.width = percentage + '%';
                    this.progressHandle.style.left = percentage + '%';
                    this.currentTime.textContent = this.formatTime(newTime);
                    
                    this.showNotification(`跳转到 ${Math.round(percentage)}%`, 'info');
                } else {
                    this.showNotification('没有可播放的录音文件或音频时长无效', 'warning');
                }
            }

            // 使用marked框架渲染markdown
            renderMarkdown(markdown) {
                if (typeof marked === 'undefined') {
                    console.error('marked框架未加载');
                    return markdown; // 降级处理
                }
                
                // 配置marked选项
                marked.setOptions({
                    breaks: true, // 支持换行
                    gfm: true, // 支持GitHub风格的markdown
                    sanitize: false, // 不清理HTML（如果需要安全，可以设为true）
                    smartLists: true,
                    smartypants: true
                });
                
                return marked.parse(markdown);
            }

            // 直接渲染markdown内容
            renderMarkdownContent(container, content, append = false, cacheKey = null) {
                if (!content || content.trim() === '') {
                    if (!append) {
                        container.innerHTML = '';
                        if (cacheKey && this.contentCache[cacheKey]) {
                            this.contentCache[cacheKey] = '';
                        }
                    }
                    return;
                }
                
                // 检查缓存，避免重复渲染相同内容
                if (cacheKey && this.contentCache[cacheKey] === content) {
                    console.log('内容未变化，跳过渲染');
                    return;
                }
                
                const html = this.renderMarkdown(content);
                
                if (append) {
                    // 追加模式：检查是否已存在相同内容，避免重复
                    const existingContent = container.innerHTML;
                    if (existingContent.includes(html.trim())) {
                        console.log('内容已存在，跳过重复渲染');
                        return;
                    }
                    container.innerHTML += html;
                } else {
                    // 替换模式：直接替换内容
                    container.innerHTML = html;
                }
                
                // 更新缓存
                if (cacheKey) {
                    this.contentCache[cacheKey] = content;
                }
                
                console.log('Markdown渲染完成', append ? '(追加模式)' : '(替换模式)', cacheKey ? `[${cacheKey}]` : '');
            }

            // 生成各标签页内容的方法
            generateWikiContent(wikiMarkdown, append = false) {
                this.renderMarkdownContent(this.wikiContent, wikiMarkdown, append, 'wiki');
            }

            generateInsightsContent(insightsMarkdown, append = false) {
                this.renderMarkdownContent(this.insightsContent, insightsMarkdown, append, 'insights');
            }

            generateKeypointsContent(keypointsMarkdown, append = false) {
                this.renderMarkdownContent(this.keypointsContent, keypointsMarkdown, append, 'keypoints');
            }

            generateTodosContent(todosMarkdown, append = false) {
                this.renderMarkdownContent(this.todosContent, todosMarkdown, append, 'todos');
            }

            // 生成洞察子项内容的方法
            generateAbstractContent(abstractMarkdown, append = false) {
                if (abstractMarkdown && abstractMarkdown.trim()) {
                    this.renderMarkdownContent(this.abstractContent, abstractMarkdown, append, 'abstract');
                    console.log('摘要内容已更新');
                }
            }

            generateAdviceContent(adviceMarkdown, append = false) {
                if (adviceMarkdown && adviceMarkdown.trim()) {
                    this.renderMarkdownContent(this.adviceContent, adviceMarkdown, append, 'advice');
                    console.log('建议内容已更新');
                }
            }

            generateRiskContent(riskMarkdown, append = false) {
                if (riskMarkdown && riskMarkdown.trim()) {
                    this.renderMarkdownContent(this.riskContent, riskMarkdown, append, 'risk');
                    console.log('风险与依赖内容已更新');
                }
            }

            // 处理音频数据用于说话人识别
            handleAudioDataForSpeakerRecognition(audioData) {
                try {
                    // 将音频数据添加到当前句子的缓冲区
                    this.sentenceAudioBuffer.push(audioData);
                } catch (error) {
                    console.error('处理音频数据失败:', error);
                }
            }

            // 执行说话人识别（在句子结束时调用）
            async performSpeakerRecognition() {
                try {
                    if (this.sentenceAudioBuffer.length === 0) {
                        console.log('没有音频数据，跳过说话人识别');
                        return;
                    }

                    console.log(`开始说话人识别，音频数据块数量: ${this.sentenceAudioBuffer.length}`);
                    console.log(`当前识别模式: ${this.speakerService.mockMode ? '模拟模式' : '真实API模式'}`);

                    // 合并音频缓冲区数据
                    const totalLength = this.sentenceAudioBuffer.reduce((sum, buffer) => sum + buffer.byteLength, 0);
                    const combinedBuffer = new ArrayBuffer(totalLength);
                    const combinedView = new Uint8Array(combinedBuffer);
                    
                    let offset = 0;
                    for (const buffer of this.sentenceAudioBuffer) {
                        combinedView.set(new Uint8Array(buffer), offset);
                        offset += buffer.byteLength;
                    }

                    console.log(`合并音频数据大小: ${totalLength} bytes`);

                    // 创建说话人信息对象
                    const speakerInfo = {
                        timestamp: Date.now(),
                        speakerId: null,
                        score: 0
                    };

                    // 调用说话人识别服务
                    const result = await this.speakerService.checkSpeaker(combinedBuffer, speakerInfo);
                    
                    if (result.success) {
                        this.currentSpeaker = result.speakerId;
                        console.log(`识别到说话人: ${result.speakerId}, 置信度: ${result.score}%`);
                        this.updateDebugInfo('说话人识别', {
                            speakerId: result.speakerId,
                            score: result.score,
                            isNewSpeaker: result.isNewSpeaker
                        });
                        
                        // 显示说话人识别结果
                        if (result.isNewSpeaker) {
                            this.showNotification(`识别到新说话人: ${result.speakerId}`, 'info');
                        } else {
                            this.showNotification(`识别到说话人: ${result.speakerId} (置信度: ${result.score}%)`, 'success');
                        }
                    } else {
                        console.log('说话人识别失败:', result.error);
                        this.updateDebugInfo('说话人识别失败', { error: result.error });
                    }

                    // 清空缓冲区
                    this.sentenceAudioBuffer = [];

                } catch (error) {
                    console.error('说话人识别失败:', error);
                    this.sentenceAudioBuffer = []; // 清空缓冲区避免积累
                }
            }



            // 清理资源
            cleanup() {
                this.stopRecording();
                this.apiService.cleanupASR();
                this.stopProgressUpdate();
                
                // 清理说话人识别相关资源
                this.sentenceAudioBuffer = [];
                this.currentSpeaker = null;
                
                // 清理音频资源
                if (this.audioUrl) {
                    URL.revokeObjectURL(this.audioUrl);
                }
                if (this.audioElement) {
                    this.audioElement.remove();
                }
            }
        }

        // 初始化应用
        document.addEventListener('DOMContentLoaded', () => {
            window.meetingAssistant = new MeetingAssistant();
        });

        // 页面卸载时清理资源
        window.addEventListener('beforeunload', () => {
            if (window.meetingAssistant) {
                window.meetingAssistant.cleanup();
            }
        });
    </script>
</body>
</html>
